/*
 *  $Id: SpriteDescriptor.cs 1203 2010-11-22 18:41:11Z thenn.erannor $
 *  This file is a part of Ragima CCG.
 *  (C) 2008-2010 Ragima development group.
 *
 *  Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System;
using System.Collections.Generic;

using AgateLib.Geometry;
using AgateLib.DisplayLib;

using Nereal.Serialization;

namespace Ragima.UI {
    /// <summary>
    /// Ориентация расположения спрайтов.
    /// </summary>
    public enum SpriteOrientation {
        Horizontal,
        Vertical
    }

    /// <summary>
    /// Описатель расположения группы спрайтов внутри большого изображения.
    /// </summary>
    [XmlRootName("sprite"), ConstructorParameters("Start", "Size", "Orientation", "Cols", "Rows")]
    public class SpriteDescriptor {
        private Point _start;
        private Size _size;
        private SpriteOrientation _orientation;
        private int _cols, _rows;

        public SpriteDescriptor(Point start, Size size, SpriteOrientation orientation, int cols, int rows) {
            _start = start;
            _size = size;
            _orientation = orientation;
            _cols = cols;
            _rows = rows;
            Correct();
        }

        /// <summary>
        /// Координаты начала спрайтов в изображении.
        /// </summary>
        [XmlName("start")]
        public Point Start {
            get { return _start; }
        }

        /// <summary>
        /// Размеры отдельного спрайта.
        /// </summary>
        [XmlName("size")]
        public Size Size {
            get { return _size; }
        }

        /// <summary>
        /// Расположение спрайтов: горизонтальное или вертикальное.
        /// </summary>
        [XmlName("orientation")]
        public SpriteOrientation Orientation {
            get { return _orientation; }
        }

        /// <summary>
        /// Количество столбцов в группе спрайтов.
        /// </summary>
        [XmlName("cols"), DefaultValue(1)]
        public int Cols {
            get { return _cols; }
        }

        /// <summary>
        /// Количество строк в группе спрайтов.
        /// </summary>
        [XmlName("rows"), DefaultValue(1)]
        public int Rows {
            get { return _rows; }
        }

        /// <summary>
        /// Общее количество спрайтов.
        /// </summary>
        public int Count {
            get { return _cols * _rows; }
        }

        /// <summary>
        /// Корректирует свойства описателя спрайтов.
        /// </summary>
        private void Correct() {
            if (_cols < 1)
                _cols = 1;
            if (_rows < 1)
                _rows = 1;
        }

        /// <summary>
        /// Выдает прямоугольник спрайта пл его номеру.
        /// </summary>
        public Rectangle GetRect(int number) {
            if (number < 0 || number >= Count)
                throw new ArgumentOutOfRangeException("number");
            int x = 0, y = 0;
            if (number > 0) {
                switch (_orientation) {
                    case SpriteOrientation.Horizontal:
                        if (_rows > 1)
                            y = Math.DivRem(number, _cols, out x);
                        else
                            x = number;
                        break;
                    case SpriteOrientation.Vertical:
                        if (_cols > 1)
                            x = Math.DivRem(number, _rows, out y);
                        else
                            y = number;
                        break;
                }
            }
            var p = _start;
            if (x > 0)
                p.X += x * _size.Width;
            if (y > 0)
                p.Y += y * _size.Height;
            var rect = new Rectangle(p, _size);
            return rect;
        }

        /// <summary>
        /// Рисует спрайт по номеру из указанного исходного изображения.
        /// </summary>
        public virtual void Draw(int number, Surface source, Point point) {
            source.Draw(GetRect(number), new Rectangle(point, _size));
        }
        /// <summary>
        /// Рисует спрайт по номеру из указанного исходного изображения.
        /// </summary>
        public void Draw(int number, Surface source, int x, int y) {
            Draw(number, source, new Point(x, y));
        }
    }

    /// <summary>
    /// Список описателей спрайтов, идентифицируемых по ID.
    /// </summary>
    [XmlRootName("sprites")]
    public class SpriteDescriptorList : DescriptorList<SpriteDescriptor> {
        [XmlName(null, "sprite")]
        public override Dictionary<string, SpriteDescriptor> Descriptors {
            get { return base.Descriptors; }
        }
    }

    /// <summary>
    /// Поверхность со спрайтами, загружается вместе с описателями спрайтов.
    /// </summary>
    public class SpriteSurface : DescriptedSurface<SpriteDescriptor, SpriteDescriptorList> {
        public SpriteSurface(string surfName) : base(surfName) {
        }

        /// <summary>
        /// Получает спрайт по идентификатору.
        /// </summary>
        public Sprite GetSprite(string id) {
            return new Sprite(Surface, GetDescriptor(id));
        }

        /// <summary>
        /// Загружает поверхность со спрайтами из указанного файла.
        /// </summary>
        public static object LoadData(string filename) {
            return new SpriteSurface(filename);
        }
    }
}
